/*******************************************************************************
 * @brief: IO预处理
 * @Author:   aple
 * @Date: 2015-09-30 08:03:56
 * @LastEditors: aple
 * @LastEditTime: 2022-12-05 13:28:04
 * @Verision: 1.0.0.0
 ******************************************************************************/
#ifndef IO_HANDLE_H_
#define IO_HANDLE_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "stdint.h"
#include "dataproc.h"
#include "key_handle.h"
#include "io_flt_sig.h"
#include "io_flt_group.h"

	/*******************************************************************************
	 * @brief  ad 转 io
	 * \param[in] sample_old: 上次判定状态
	 * \param[in] ad_true: 真值AD边界下限
	 * \param[in] ad_false: 假值AD边界上限
	 * \param[in] ad_now: 当前AD值
	 * \retval: 判定状态
	 *******************************************************************************/
	uint8_t ad_io_creat(uint8_t sample_old, uint16_t ad_true, uint16_t ad_false, uint16_t ad_now);

	/*******************************************************************************
	 * @brief  AD 过采样
	 *******************************************************************************/
	struct ad_filter_str
	{
		uint8_t sum_list_index; // sum列表当前位置
		uint8_t sum_list_len;	// sum列表长度
		uint16_t *sum_list;		// sum值列表
		uint32_t *sum_now;		// 当前sum值
		uint8_t sample_cnt;		// 每个sum值采样计数值
		uint8_t sample_set;		// 每个sum值采样次数设定值
		uint8_t sum_shift_bits; // sum 存储时右移位数
		uint8_t ch_amount;		// 通道数
		uint8_t b_end_st;		// 当此sum完成标志，外部清除
	};
	typedef struct ad_filter_str ad_filter_type;
	void ad_oversampling(ad_filter_type *obj, uint16_t ad_now[]);

	/*******************************************************************************
	 * @brief  输出映射表结构
	 *******************************************************************************/
	struct out_obj_struct
	{
		void (*en)(void);
		void (*dis)(void);
		void (*tog)(void);
		uint8_t (*out_st)(void);
	};

	typedef struct out_obj_struct out_obj_type;

	/*****************************************************************************
	 * @brief	信号信息
	 *****************************************************************************/
	struct io_signal_struct
	{
		uint8_t sig;
		uint8_t sig_old;
		uint8_t edge, edge_found, edge_lost;
		uint16_t found_time_cnt;
		uint16_t lost_time_cnt;
	};

	typedef struct io_signal_struct io_signal_type;

	uint8_t io_signal_info_handle(io_signal_type *io_obj, uint8_t time_pulse, uint8_t sig_new);

	struct out_st_struct
	{
		uint8_t time_pulse; // 计时脉冲
		uint8_t old;
		uint8_t enable_edge;
		uint8_t disable_edge;
		uint32_t enable_time_cnt;  // 0-UINT32_MAX
		uint32_t disable_time_cnt; // 0-UINT32_MAX
	};

	typedef struct out_st_struct out_st_type;

	struct out_stv2_struct
	{
		uint8_t out; // 计时脉冲
		uint8_t old;
		uint8_t enable_edge;
		uint8_t disable_edge;
		uint32_t enable_time_cnt;  // 0-UINT32_MAX
		uint32_t disable_time_cnt; // 0-UINT32_MAX
	};

	typedef struct out_stv2_struct out_stv2_type;

	struct simp_out_st_struct
	{
		uint8_t time_pulse : 1; // 计时脉冲
		uint8_t old : 1;
		uint8_t enable_edge : 1;
		uint8_t disable_edge : 1;

		uint16_t enable_time_cnt;  // 0-UINT16_MAX
		uint16_t disable_time_cnt; // 0-UINT16_MAX
	};

	typedef struct simp_out_st_struct simp_out_st_type;

	// 以下两者功能相同，结构区别。 边沿+计时
	void out_st_handle(out_st_type *obj, uint8_t out_now);		  // 允许多任务使用
	void out_stv2_handle(out_stv2_type *obj, uint8_t time_pulse); // 允许多任务使用

	// 边沿+计时，使用位域
	void simp_out_st_handle(simp_out_st_type *obj, uint8_t out_now); // 不可在多任务中使用

	/*****************************************************************************
	 * @brief	分组边沿发生器
	 *****************************************************************************/
	typedef struct
	{
		word_tt old;
		word_tt edge, edge_found, edge_lost;
	} u16_group_edge_type;

	typedef struct
	{
		dword_tt old;
		dword_tt edge, edge_found, edge_lost;
	} u32_group_edge_type;

	uint16_t u16_group_edge_gen(u16_group_edge_type *obj, uint16_t rt_val);
	uint32_t u32_group_edge_gen(u32_group_edge_type *obj, uint32_t rt_val);

/*****************************************************************************
 * @brief	输出状态切换管理
 *****************************************************************************/
#define OUT_SW_EN 0x01
#define OUT_SW_DIS 0x02
#define OUT_SW_REQ 0x03

	struct out_sw_struct
	{
		uint8_t out;	  // RO
		uint8_t en_edge;  // RO
		uint8_t dis_edge; // RO
		uint8_t req;	  // Y手动请求. [1] 关闭，[2]开启，[3]切换，
		uint32_t time;	  // RO //内部计数最大为2^32，溢出归零
	};

	typedef struct out_sw_struct out_sw_type;

	/* time_sv 设为0不切换该状态,对应req同时失效.设为其他值保持设定数值脉冲数，设定值>2^31时，保持在该状态，除非手动req    */
	/* pulse 为计时脉冲                                           */
	uint8_t out_sw_manage(out_sw_type *out_obj, uint32_t en_time_sv, uint32_t dis_time_sv, uint8_t pulse);
	void out_sw_reset(out_sw_type *out_obj, uint8_t out_init);

	/*****************************************************************************
	 * @brief	补水管理
	 *****************************************************************************/
	struct wt_add_struct
	{
		uint8_t run_st;	   // Y-运行控制
		uint8_t low_st;	   // Y-低水位状态，低于低水位开始补水
		uint8_t high_st;   // Y-高水位状态，达到高水位延时停机
		uint8_t out;	   // X-补水状态输出
		uint8_t err;	   // X-补水超时标志，水位正常自动清零
		uint8_t comp;	   // X-Y0 补水过程清0，完成置1;可外部清零
		uint16_t en_time;  // X 输出计时
		uint16_t dly_time; // X 延时计时
	};

	typedef struct wt_add_struct wt_add_type;

	/* ot_time_sv  为0时无补水功能，强制清零所有状态 */
	/* pulse 为计时脉冲                                           */
	uint8_t wt_add_manage(wt_add_type *out_obj, uint16_t ot_time_sv, uint16_t dly_time_sv, uint8_t pulse);

	/*****************************************************************************
	 * @brief	双输出切换管理
	 *****************************************************************************/
	struct dev_double_sw_struct
	{
		uint8_t out0;			  // X
		uint8_t out1;			  // X
		uint8_t mode;			  // Y 0-关闭，1out0,2-out1, 其他切换
		uint8_t out_sel;		  // X
		int32_t out0_en_time;	  // X
		int32_t out0_dis_time;	  // X
		int32_t out1_en_time;	  // X
		int32_t out1_dis_time;	  // X
		int32_t delay_cnt;		  // X
		int32_t dev_off_min_time; // Y 设备最小停机时间
	};

	typedef struct dev_double_sw_struct dev_double_sw_type;

	/*****************************************************************************-/
	 * @brief   Double cool time handle.
	 *          switch_time 必须大于 switch_time_befor+mintime，否则将强制switch_time = switch_time_befor+mintime
	 * @param   dev： obj
	 * @param   switch_time_set : switch time
	 * @param   switch_time_befor : 正数 before-time, 负数delay-time
	 * @param   pulse : 计时脉冲
	 *****************************************************************************/
	void dev_double_sw(dev_double_sw_type *dev, int32_t switch_time_set, int32_t switch_time_befor, uint8_t pulse);

	/*----正反转控制----*/
	typedef enum
	{
		C_ST_NC_STOP = 0,
		C_ST_CC_RUN = 1,
		C_ST_CC_STOP = 2,
		C_ST_NC_RUN = 3,
	} nc_cc_sw_st_type;

	struct nc_cc_sw_struct
	{
		nc_cc_sw_st_type st;	   // X 输出状态
		nc_cc_sw_st_type st_start; // Y 起始状态
		uint32_t cct_set;		   // Y 正转时间
		uint32_t nct_set;		   // Y 反转时间
		uint32_t sot_set;		   // Y 停止时间
		uint32_t spd_now;		   // Y 当前转速
		uint32_t spd_set;		   // Y 设定转速
		uint32_t time_cnt;		   // X 计时值，正计时
        uint16_t cycle;		       // X 循环次数
        uint8_t steady;            // X 稳定状态
        uint8_t time_mode;         // Y 计时方式，1 稳定计时
	};

	typedef struct nc_cc_sw_struct nc_cc_sw_type;

	// 顺序为 C_ST_NC_STOP->C_ST_CC_RUN->C_ST_CC_STOP->C_ST_NC_RUN, 某段时间设为0则跳过,STOP不可跳过，0时如果切换方向也要等待spdnow为0----
	//  cct和nct同时为0时强制为start输出----
	nc_cc_sw_st_type nc_cc_sw_handle(nc_cc_sw_type *obj, uint8_t en, uint8_t pulse);

	/*****************************************************************************
	 * @brief	加减速控制
	 *****************************************************************************/
	struct spd_inc_struct
	{
		uint32_t spd_now;		   // Y测量转速
		uint32_t spd_set;		   // Y设定转速
		uint32_t spd_out;		   // X当前输出转速设定
		uint32_t spd_up;		   // Y增速
		uint32_t spd_dn;		   // Y减速
		uint32_t spd_min;		   // Y最小转速
		uint8_t pwm_out_under_min; // Y输出小于下限值标记----
	};

	typedef struct spd_inc_struct spd_inc_type;

	uint32_t spd_inc_handle(spd_inc_type *obj, uint8_t pulse);

	/*****************************************************************************
	 * @brief	蜂鸣器输出管理
	 *****************************************************************************/
	struct beep_notice_struct
	{
		union
		{
			uint32_t st; // 请求状态
			struct
			{
				uint8_t micro_x;  // 输出次数请求。周期4，方波50%输出-
				uint8_t short_x;  // 输出次数请求。周期8，方波50%输出-
				uint8_t middle_x; // 输出次数请求。周期16，方波50%输出-
				uint8_t auto_x;	  // 自定义请求，次数
			} mode;
		} req;

		uint8_t auto_period; // 自定义请求，周期
		uint8_t auto_duty;	 // 自定义请求，占空比
		uint8_t pulse_cnt;	 // base bpulse
		uint8_t b_beep_st;	 // 输出状态-
	};

	typedef struct beep_notice_struct beep_notice_type;

	void beep_handle(beep_notice_type *obj, uint8_t bpulse);
	void beep_clear(beep_notice_type *obj);
	void beep_auto_req(beep_notice_type *obj, uint8_t req_cnt, uint8_t period, uint8_t duty);
	void beep_micro_req(beep_notice_type *obj, uint8_t req_cnt);
	void beep_short_req(beep_notice_type *obj, uint8_t req_cnt);
	void beep_middle_req(beep_notice_type *obj, uint8_t req_cnt);

	/*****************************************************************************
	 * @brief	比较输出管理
	 *****************************************************************************/
	struct comp_out_struct
	{
		uint8_t run_st;	  // Y
		uint8_t out;	  // X
		uint8_t out_edge; // X 输出变化边沿
		int8_t dir;		  // X -1下降，1上升，0未知
		lag16_type lag;	  // XY 迟滞
		int16_t lag_rang; // Y 迟滞范围

		int16_t sv;			// Y
		int16_t pv;			// Y
		int16_t en_offset;	// Y
		int16_t dis_offset; // Y
		int16_t vd_dir;		// X
	};

	typedef struct comp_out_struct comp_out_type;

	uint8_t comp_out_handle(comp_out_type *obj, uint8_t dir_adj_pulse);		// 正作用
	uint8_t comp_out_nev_handle(comp_out_type *obj, uint8_t dir_adj_pulse); // 反作用

/*****************************************************************************
* @brief   时间序列联动
*****************************************************************************/
typedef struct
{
	uu08 st;  // [Y] 执行状态。[1]:通电顺序out1->out2；[0]断电顺序out2->out1
	uu08 st_old; // [x] 状态记录
	uu08 out1, out2; // [x] 输出状态
	uu16 tick_start; // [x] 计时开始时刻，通过心跳差值计时
} sequence_linkage_type;

/*****************************************************************************
* @brief   页面管理
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void sequence_linkage_manage(sequence_linkage_type *obj, uu16 ticks, uu16 delay);

/*****************************************************************************
 * @brief	输出执行管理
 *****************************************************************************/
#define OUT_EXE_STEP_IDLE 0
#define OUT_EXE_STEP_OUT 1
#define OUT_EXE_STEP_DLY 2
#define OUT_EXE_STEP_SPACE 3

	struct out_exe_struct
	{
		// input
		uint8_t req;			// 执行请求
		uint8_t condition;		// 执行允许条件
		uint8_t st_back;		// 执行结果返回
		uint8_t exe_max;		// 执行失败最大次数
		uint16_t exe_time_ot;	// 执行超时时间设定值
		uint16_t exe_time_dly;	// 执行延时时间设定值，反馈信号后延时关闭
		uint16_t space_time_sv; // 执行间隔设定值（多次执行时有效）

		// output
		uint16_t tick_start; // 执行开始时刻，通过心跳差值计时
		uint8_t exe_step;  // 执行步骤
		uint8_t exe_cnt;   // 执行记数
		uint8_t err;	   // 执行失败 //st_back有效自动清除。可外部清除，清除前无法重启
		uint8_t out;	   // 输出状态
	};

	typedef struct out_exe_struct out_exe_type;

	void out_exe_handle(out_exe_type *obj, uint16_t ticks);

#ifdef __cplusplus
}
#endif

#endif /* IO_HANDLE_H_ */
